package com.bjy.qa.service.project.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bjy.qa.dao.project.JobDao;
import com.bjy.qa.entity.MyPage;
import com.bjy.qa.entity.ResponsePagingData;
import com.bjy.qa.entity.project.Job;
import com.bjy.qa.enumtype.JobStatus;
import com.bjy.qa.enumtype.JobType;
import com.bjy.qa.exception.MyException;
import com.bjy.qa.quartz.QuartzHandler;
import com.bjy.qa.service.project.IJobService;
import org.apache.commons.lang.StringUtils;
import org.quartz.CronTrigger;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class JobService extends ServiceImpl<JobDao, Job> implements IJobService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    JobDao jobDao;

    @Resource
    QuartzHandler quartzHandler;

    @Override
    public ResponsePagingData list(MyPage<Job> myPage) {
        Page<Job> page = new Page(myPage.getPageNum(), myPage.getPageSize()); // 构造待查询 page 对象
        page.setOrders(myPage.getOrders()); // 设置排序字段

        // 构造待查询 QueryWrapper
        Job job = myPage.getQuery();
        QueryWrapper<Job> queryWrapper = new QueryWrapper<>();
        if (job != null) {
            if (job.getProjectId() == null) { // 查询系统 job
                queryWrapper.eq("type", JobType.SYSTEM_JOB.getValue());
            } else { // 查询 project job
                queryWrapper.eq("project_id", job.getProjectId());
            }
            if (StringUtils.isNotBlank(job.getName())) {
                queryWrapper.like("name", job.getName());
            }
        }
        queryWrapper.orderByDesc("id");

        page = jobDao.selectPage(page, queryWrapper); // 按分页查询

        myPage.setTotalRecords(page.getTotal()); // 设置返回总记录数

        return new ResponsePagingData(myPage, page.getRecords());
    }

    @Override
    public Object add(Job job) {
        jobDao.insert(job);
        CronTrigger trigger = quartzHandler.getTrigger(job);
        try {
            if (trigger != null) {
                quartzHandler.updateScheduleJob(job);
            } else {
                quartzHandler.createScheduleJob(job);
            }
        } catch (RuntimeException | SchedulerException e) {
            e.printStackTrace();
            throw new MyException("新增定时任务失败 " + e.getMessage());
        }
        return job;
    }

    @Override
    public Object update(Job job) {
        // 更新数据需要清除 UpdatedTime 和 CreatedTime，否则不会自动更新修改时间
        job.setUpdatedAt(null);
        job.setCreatedAt(null);

        jobDao.updateById(job);

        CronTrigger trigger = quartzHandler.getTrigger(job);
        try {
            if (trigger != null) {
                quartzHandler.updateScheduleJob(job);
            } else {
                quartzHandler.createScheduleJob(job);
            }
        } catch (RuntimeException | SchedulerException e) {
            e.printStackTrace();
            throw new MyException("修改定时任务失败 " + e.getMessage());
        }
        return job;
    }

    @Override
    public int delete(Long id) {
        Job job = jobDao.selectById(id);
        try {
            quartzHandler.deleteScheduleJob(job);
        } catch (SchedulerException e) {
            throw new MyException("删除定时任务失败 " + e.getMessage());
        }

        return jobDao.deleteById(id);
    }

    @Override
    public Object updateStatus(Long projectId, Long id, JobStatus status) throws SchedulerException {
        Job job = jobDao.selectById(id);
        if (job != null) {
            switch (status) {
                case ONCE:
                    quartzHandler.runScheduleJob(job);
                    return "定时任务开始运行！";
                case ON:
                    quartzHandler.resumeScheduleJob(job);
                    job.setStatus(JobStatus.ON.getValue());
                    jobDao.updateById(job);
                    return "定时任务已启用！";
                case OFF:
                    quartzHandler.pauseScheduleJob(job);
                    job.setStatus(JobStatus.OFF.getValue());
                    jobDao.updateById(job);
                    return "定时任务已停用！";
            }
        }
        return "定时任务设置失败，定时任务不存在！";
    }

    @Override
    public Object initSystemJob() throws SchedulerException {
        initSystemJob("cleanDeleted", "清除已删除的数据", "0 10 0 * * ?"); // 清除已删除的数据, 每天 0:10 执行
        initSystemJob("cleanTestResult", "清除测试报告", "0 30 0 * * ?"); // 清除测试报告, 每天 0:30 执行
        initSystemJob("testCaseCount","数据统计-用户对应测试用例维度", "0 30 23 * * ?"); // 数据统计-用户对应测试用例维度，每天23:30
        return true;
    }

    /**
     * 初始化一个系统定时任务
     * @param jobKey 定时任务的 key
     * @param jobName 定时任务的名称
     * @param cronExpression 定时任务的 cron 表达式
     * @return
     * @throws SchedulerException
     */
    private Object initSystemJob(String jobKey, String jobName, String cronExpression) throws SchedulerException {
        QueryWrapper<Job> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type", JobType.SYSTEM_JOB.getValue());
        queryWrapper.eq("run_user", jobKey);
        if (jobDao.selectCount(queryWrapper) == 0) {
            logger.info("初始化系统定时任务: {}", jobKey);
            // 创建 job 表数据
            Job job = new Job();
            job.setType(JobType.SYSTEM_JOB.getValue());
            job.setStatus(JobStatus.ON.getValue());
            job.setName(jobName);
            job.setCronExpression(cronExpression);
            job.setProjectId(0L);
            job.setTaskId(0L);
            job.setUserId(0L);
            job.setRunUser(jobKey);
            jobDao.insert(job);

            // 创建定时任务
            CronTrigger trigger = quartzHandler.getTrigger(job);
            try {
                if (trigger != null) {
                    quartzHandler.updateScheduleJob(job);
                } else {
                    quartzHandler.createScheduleJob(job);
                }
            } catch (RuntimeException | SchedulerException e) {
                e.printStackTrace();
                throw new MyException("新增定时任务失败 " + e.getMessage());
            }
        }
        return true;
    }
}
